package presenter;
import graphic.ControlGUI;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;

import network.ChatNI;
import model.Model;
import model.User;

import signals.*;


public class Presenter {

	private ChatNI nI;
	//private ChatGUI gUI;
	private ControlGUI gUI;
	private Model mod;
	private int portUDP;
	private int portEcouteTCP;
	private int noFileSend;
	private ArrayList<String> filesTransfered;
	private boolean downloading;
	
	
	public Presenter() {
		this.portUDP=5500;
		this.portEcouteTCP = 6500;
		nI= new ChatNI(this,portUDP,portEcouteTCP);
		mod = new Model();
		noFileSend = 0;
		this.filesTransfered = new ArrayList<String>();
		//gUI= new ChatGUI(this);
		gUI = new ControlGUI(this);
		this.downloading=false;
	}
	
	
	private InetAddress getAddrByN (String adr) {
		InetAddress addr = null;
		try {
			addr = InetAddress.getByName(adr);
		} catch (UnknownHostException e) {			
			e.printStackTrace();
		}
		return addr;
	}
	
	private boolean isLocalUser (String user, InetAddress addr) {
		if (mod.LocalUserBind()){
			return (user.equals(mod.getLocalUser()) || addr.toString().equals(mod.getLocalAddress()));
		}
		else return (user.equals(mod.getLocalUser()) || addr==getAddrByN("localhost"));
	}
	
	private boolean isKnown(String addr){
		return mod.existsInList(addr);
	}
	
	public ArrayList<User> getUserList() {
		return mod.getUserList();
	}
	
	
	
	//########## from NETWORK ########## 
	public void processHello(Hello s, InetAddress addrD) {
		if (isLocalUser(s.getUsername(),addrD)) {
			mod.addUser("me", addrD.toString());
			mod.defineLocalAddress(addrD.toString());
			gUI.showLocalConnect(mod.getLoginByInetAddr(addrD));
		}
		else {
			if (!isKnown(addrD.toString())){
				mod.addUser(s.getUsername(), addrD.toString());
				gUI.showConnect(mod.getLoginByInetAddr(addrD));
			}
			HelloReply h = new HelloReply(mod.getLocalUser());
			nI.sendSignalUDP(h, portUDP, addrD);
		}
	}

	public void processHelloReply(HelloReply s, InetAddress addrD) {		
		if (isKnown(addrD.toString())){			
		}
		else{
			if (isLocalUser(s.getUsername(),addrD)){
				mod.addUser("me", addrD.toString());
			}
			else{
			mod.addUser(s.getUsername(), addrD.toString());
			gUI.showConnect(mod.getLoginByInetAddr(addrD));
			}
		}		
	}

	public void processAskLogin(AskLogin s, InetAddress addrD) {		
		HelloReply h = new HelloReply(mod.getLocalUser());
		nI.sendSignalUDP(h, portUDP, addrD);
	}

	public void processGoodBye(GoodBye s, InetAddress addrD) {		
		if (mod.existsInList(addrD.toString())){
			gUI.showDisconnect(mod.getLoginByInetAddr(addrD));			
			mod.rmvUser(addrD);
		}		
	}

	public void processSendText(SendText s, InetAddress addrD) {		
		if (!isKnown(addrD.toString())){
			performAskLogin(addrD);
		}
		gUI.showText(mod.getLoginByInetAddr(addrD),s.getMessage());		
	}

	public void processAcceptFile(AcceptFile s, InetAddress addrD) {
		if (s.accepted()) {
			if (s.now()){
				gUI.showText(mod.getLoginByInetAddr(addrD), "Transfer accepted, will begin soon.");
				nI.sendFileTCP(mod.getFilePath(this.filesTransfered.get(s.getFileID())),addrD,portEcouteTCP);
			}
			else gUI.showText(mod.getLoginByInetAddr(addrD), "Transfer accepted. Waiting for distant user to be ready");
		}
		else gUI.showText(mod.getLoginByInetAddr(addrD), "File transfer declined");
	}
	
	public void processPropFile(PropFile s, InetAddress addrD) {
		if (!isKnown(addrD.toString())){
			performAskLogin(addrD);			
		}
		gUI.showPropFile(s.getFileName(),s.getFileSize(),s.getFileID(),mod.getLoginByInetAddr(addrD));
	}

	
	
	//########## from USER ########## 
	public void performConnect (String login) {
		mod.defineLocalUser(login);
		performHello(login);
	}
	
	public void performHello(String login) {
		Hello h = new Hello(login);
		nI.sendSignalUDP(h, portUDP, getAddrByN("255.255.255.255"));
	}
	
	public void performGoodBye () {
		GoodBye s = new GoodBye();
		nI.sendSignalUDP(s, portUDP, getAddrByN("255.255.255.255"));
	}
	
	public void performSendText(String text, String[] users){
		int i; InetAddress current;
		SendText s = new SendText(text,mod.getAddrsByName(users));
		for(i=0;i<s.getReceivers().length;i++){
			current = s.getReceivers()[i];
			nI.sendSignalUDP(s, portUDP, current);
		}
	}
		
	public void performDisconnect () {
		performGoodBye();
		mod.clearList();
		gUI.showLocalDisconnect();
	}
	
	public void performAskLogin(InetAddress addr){
		AskLogin s = new AskLogin();
		nI.sendSignalUDP(s, portUDP, addr);
	}
	
	public void performAcceptFile(int fileID, boolean accept, boolean sendNow,
			String login, String path) {
		AcceptFile s = new AcceptFile(fileID,accept,sendNow);
		nI.sendSignalUDP(s, portUDP, getAddrByN(mod.getAddrByLogin(login)));
		while (this.downloading){}
		nI.recvFileTCP(path);
		this.downloading=true;
	}
	
	public void performPropFile(String fileName, long fileSize, String login, String path) {
		PropFile s = new PropFile(fileName, fileSize, noFileSend);
		mod.addFile(fileName, path);
		this.filesTransfered.add(fileName);
		noFileSend++;
		nI.sendSignalUDP(s, portUDP, getAddrByN(mod.getAddrByLogin(login)));		
	}


	public void processDLComplete(InetAddress iAddr) {
		gUI.showText(mod.getLoginByInetAddr(iAddr), "Download Complete.");
		this.downloading=false;
	}

	



}
